/************************************************************************/
/* Name : Kiwon Yun
/* Partner's name : Eric Rooney
/* File Name : RuleManager.cpp
/* The name of assignment : Iteration 2
/************************************************************************/

#include "RuleManager.h"
#include "Player.h"
#include "Hand.h"

struct GreaterValue
{
	bool operator()(Card* a_card1, Card* a_card2) const
	{
		string str1 = a_card1->value;
		string str2 = a_card2->value;

		int nVal1 = ConvertCardValueToInteger(str1);
		int nVal2 = ConvertCardValueToInteger(str2);

		if( nVal1 >= nVal2 )
			return false;
		else
			return true;
	}

};

template <typename _Pair>
struct ComparePairByFirstDesc {
public:
	bool operator()(const _Pair &LHS, const _Pair &RHS) 
	{
		if( LHS.first == RHS.first )
			return (LHS.second > RHS.second);
		else
			return (LHS.first > RHS.first);
	}
};

//////////////////////////////////////////////////////////////////////////

RuleManager::RuleManager(void)
{
}

RuleManager::~RuleManager(void)
{
}

Player* RuleManager::SelectWinner( Player* a_pPlayer1, Player* a_pPlayer2 )
{
	bool bCheckPlayer2 = true;

	Player* pWinner;

	RankScore* pRankScore1 = NULL;
	RankScore* pRankScore2 = NULL;
	
	pRankScore1 = GetRankScore( a_pPlayer1->GetHand() );
//	cout << "CurPlayer's Score : ";
	PrintRankScore( pRankScore1 );

	if( a_pPlayer2 == NULL )
	{
		bCheckPlayer2 = false;
		pWinner = a_pPlayer1;
	}
	else
	{
		pRankScore2 = GetRankScore( a_pPlayer2->GetHand() );
//		cout << "PreWinner's Score : ";
//		PrintRankScore( pRankScore2 );

		RankScore* pWinnerRankScore = GetWinnerRankScore( pRankScore1, pRankScore2 );

		// Two players are tied
		if( pWinnerRankScore == NULL )
		{
			pWinner = NULL;
		}
		else if( pWinnerRankScore == pRankScore1 )
		{
			pWinner = a_pPlayer1;
		}
		else if( pWinnerRankScore == pRankScore2 )
		{
			pWinner = a_pPlayer2;
		}
	}

	if( pRankScore1 )
	{
		delete pRankScore1;
		pRankScore1 = NULL;
	}

	if( pRankScore2 )
	{
		delete pRankScore2;
		pRankScore2 = NULL;
	}

	return pWinner;
}

RankScore* RuleManager::GetRankScore( Hand* a_pHand )
{
	RankScore* pRankScore = new RankScore;

	if( CheckAllCardsAreSameSuit( a_pHand, pRankScore ) )
	{
		if( CheckAllCardsAreOrdered( a_pHand, pRankScore ) )
			pRankScore->ranking = StraitFlush;
		else
			pRankScore->ranking = Flush;
	}
	else
	{
		if( CheckAllCardsAreOrdered( a_pHand, pRankScore ) )
			pRankScore->ranking = Strait;
		else
			pRankScore->ranking = CheckCardsAreSameValue( a_pHand, pRankScore );
	}

	return pRankScore;
}

bool RuleManager::CheckAllCardsAreSameSuit( Hand* a_pHand, RankScore* a_pRankScore )
{
	Card* cards[5];
	cards[0] = a_pHand->GetCard(0);
	char cardsSuit = cards[0]->suit;

	for( int i = 1; i < 5; i++ )
	{
		cards[i] = a_pHand->GetCard(i);
		if( cardsSuit != cards [i]->suit )
		{
			return false;
		}
	}

	// save score if rank is flush
	VecInt vecTempValue;
	for( int i = 0; i < 5; i++ )
	{
		Card* curCard = a_pHand->GetCard(i);
		int nCurValue = ConvertCardValueToInteger( curCard->value );
		vecTempValue.push_back( ConvertIntegerToScore( nCurValue ) );
	}

	sort( vecTempValue.begin(), vecTempValue.end(), greater<int>() );
	a_pRankScore->nScore = GetScore( vecTempValue );

	return true;
}

bool RuleManager::CheckAllCardsAreOrdered( Hand* a_pHand, RankScore* a_pRankScore )
{
	vector <Card*> vecTempCard; 
	for( int i = 0; i < 5; i++ )
	{
		vecTempCard.push_back( a_pHand->GetCard(i) );
	}

	sort( vecTempCard.begin(), vecTempCard.end(), GreaterValue() );
	
	vector <Card*>::iterator it;
	it = vecTempCard.begin();
	Card* pCard = (*it);
	string preValue = pCard->value;
	int nPre = ConvertCardValueToInteger( preValue );
	it++;

	bool bIncludeAce = false;
	if( nPre == 1 )
		bIncludeAce = true;

	bool bAceMean14 = false;

	while ( it != vecTempCard.end() ) 
	{
		pCard = (*it);
		string curValue = pCard->value;

		int nCur = ConvertCardValueToInteger( curValue );
		nPre = ConvertCardValueToInteger( preValue );

		if( bIncludeAce && nPre == 1 )
		{
			if( nCur != 2 )
			{
				bAceMean14 = true;
			}
		}
		else
		{
			if( nCur != nPre + 1 )
				return false;
		}

		preValue = curValue;
		it++;
	}

	if( bIncludeAce && bAceMean14 )
	{
		string lastValue = pCard->value;
		if( lastValue.compare("K") )
		{
			return false;
		}
	}

	// save score if rank is strait
	VecInt vecTempValue;
	for( int i = 0; i < 5; i++ )
	{
		Card* curCard = a_pHand->GetCard(i);
		int nCurValue = ConvertCardValueToInteger( curCard->value );

		if( bAceMean14 )
			vecTempValue.push_back( ConvertIntegerToScore(nCurValue) );
		else
			vecTempValue.push_back( nCurValue );
	}

	sort( vecTempValue.begin(), vecTempValue.end(), greater<int>() );

	// calculate score just using highest value
	VecInt vecValue;
	vecValue.push_back( vecTempValue[0] );
	a_pRankScore->nScore = GetScore( vecValue );

	return true;
}

Ranking RuleManager::CheckCardsAreSameValue( Hand* a_pHand, RankScore* a_pRankScore )
{
	vector < pair<int, int> > vecPair;

	// check the number of cards that have the same value.
	vector <int> vecValueCount;
	vector <int> vecValue;
	for( int j = 0; j < 13; j++ )
	{
		vecValueCount.push_back( 0 );
	}

	for( int i = 0; i < 5; i++ )
	{
		Card* curCard = a_pHand->GetCard(i);
		int nValue = ConvertCardValueToInteger( curCard->value );

		vecValue.push_back( nValue );
		vecValueCount[ nValue - 1 ]++;
	}

	// save the value that exists more than one (it means pair)
	int nMaxValue = 0;
	int nIndex = 0;
	vector <int>::iterator it;
	for( it = vecValueCount.begin(); it != vecValueCount.end(); it++ )
	{
		nIndex++;
		int nCurValue = (*it);

		if( nCurValue <= 1 )
			continue;

		pair<int, int> pairVal;
		pairVal.first = nCurValue;
		pairVal.second = ConvertIntegerToScore(nIndex);

		vecPair.push_back( pairVal );
	}

	// save score about the pair cards (the more existing card is saved first)
	sort( vecPair.begin(), vecPair.end(), ComparePairByFirstDesc< pair<int, int> >() );

	VecInt vecScoreValue;
	vector< pair<int, int> >::iterator itPair;
	for( itPair = vecPair.begin(); itPair != vecPair.end(); itPair++ )
	{
		pair<int, int> pairScoreVal;
		pairScoreVal = (*itPair);
		vecScoreValue.push_back( pairScoreVal.second );
	}

	// save the rest cards that are not pair into vector
	vector <int> vecRest;
	for( int i = 0; i < 5; i++ )
	{
		Card* curCard = a_pHand->GetCard(i);
		int nValue = ConvertCardValueToInteger( curCard->value );
		
		VecInt::iterator result;
		result = find( vecScoreValue.begin(), vecScoreValue.end(), ConvertIntegerToScore(nValue) );

		if( result == vecScoreValue.end() )
			vecRest.push_back( ConvertIntegerToScore(nValue) );
	}

	// save score about the rest cards (the more valuable card is saved first)
	sort( vecRest.begin(), vecRest.end(), greater<int>() );
	
	vector <int>::iterator itRest;
	for( itRest = vecRest.begin(); itRest != vecRest.end(); itRest++ )
	{
		int nRestValue = (*itRest);
		vecScoreValue.push_back( nRestValue );
	}

	// calculate a score
	a_pRankScore->nScore = GetScore( vecScoreValue );

	// calculate ranking
	int nMaxCount = 0;
	if( vecPair.size() > 0 )
	{
		pair<int, int> pairHighest = vecPair[0];
		nMaxCount = pairHighest.first;
	}

	if( nMaxCount == 4 )
		return FourOfAKind;
	else if( nMaxCount == 3 )
	{
		if( vecPair.size() > 1 )
			return FullHouse;
		else
			return ThreeOfAKind;
	}
	else if( nMaxCount == 2 )
	{
		if( vecPair.size() > 1 )
			return TwoPair;
		else
			return OnePair;
	}

	return HighCard;
}

void RuleManager::PrintRankScore( RankScore* a_pRankScore )
{
	cout << "## ";
	switch( a_pRankScore->ranking ) {
	case StraitFlush:
		cout << "StraitFlush";
		break;
	case FourOfAKind:
		cout << "FourOfAKind";
		break;
	case FullHouse:
		cout << "FullHouse";
		break;
	case Flush:
		cout << "Flush";
		break;
	case Strait:
		cout << "Strait";
		break;
	case ThreeOfAKind:
		cout << "ThreeOfAKind";
		break;
	case TwoPair:
		cout << "TwoPair";
		break;
	case OnePair:
		cout << "OnePair";
		break;
	case HighCard:
		cout << "HighCard";
		break;
	}

//	cout << "Score : " << a_pRankScore->nScore << endl;

	cout << " ##" << endl;
}

RankScore* RuleManager::GetWinnerRankScore( RankScore* a_pRankScore1, RankScore* a_pRankScore2 )
{
	if( a_pRankScore1->ranking < a_pRankScore2->ranking )
	{
		return a_pRankScore1;
	}
	else if( a_pRankScore1->ranking > a_pRankScore2->ranking )
	{
		return a_pRankScore2;
	}
	else
	{
		if( a_pRankScore1->nScore < a_pRankScore2->nScore )
		{
			return a_pRankScore2;
		}
		else if( a_pRankScore1->nScore > a_pRankScore2->nScore)
		{
			return a_pRankScore1;
		}
		else
		{
			return NULL;
		}
	}
}

int RuleManager::GetScore( VecInt a_vecValue )
{
	int nTotalScore = 0;
	int nCipher = (int)a_vecValue.size() - 1;

	vector <int>::iterator it;
	for( it = a_vecValue.begin(); it != a_vecValue.end(); it++ )
	{
		int nCurValue = (*it);
		nTotalScore += (int)pow( 14.0f, nCipher ) * nCurValue;
		nCipher--;
	}

	return nTotalScore;
}

int RuleManager::ConvertIntegerToScore( int a_nInteger )
{
	if( a_nInteger == 1 )
		return 14;
	else
		return a_nInteger;
}
